package com.huice.seller.common.result;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collection;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

@Data
@NoArgsConstructor
public class Result<T> {
    public static final int SUCCESS = 200;
    private int code;
    private String msg;
    private T data;

    private Result(int code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    public static <T> Result<T> ok() {
        return new Result(SUCCESS, null, null);
    }

    public static <T> Result<T> ok(T data) {
        return new Result(SUCCESS, data, null);
    }

    public static <T> Result<T> ok(T data, String msg) {
        return new Result(SUCCESS, data, msg);
    }

    public static <T> Result<T> error(int code, String errorMsg) {
        return new Result(code, null, errorMsg);
    }

    public static <T> Result<T> error(int code, String errorMsg, T data) {
        return new Result(code, data, errorMsg);
    }


    public static <T> Result<T> error(Result<?> result) {
        return new Result(result.getCode(), null, result.getMsg());
    }


    public <U> Result<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        return this.isFailure() ? error(this.code, this.msg) : ok(mapper.apply(this.data));
    }

    public void ifSuccess(Consumer<Result<T>> consumer) {
        Objects.requireNonNull(consumer);
        if (this.isSuccess()) {
            consumer.accept(this);
        }

    }

    public void ifPresent(Consumer<Result<T>> consumer) {
        Objects.requireNonNull(consumer);
        if (this.isPresent()) {
            consumer.accept(this);
        }

    }

    public boolean isSuccess() {
        return SUCCESS == this.code;
    }

    public boolean isFailure() {
        return !this.isSuccess();
    }

    public boolean isPresent() {
        return this.isSuccess() && this.data != null && this.isNotEmpty();
    }

    private boolean isNotEmpty() {
        if (this.data instanceof Collection) {
            return ((Collection) this.data).size() > 0;
        } else {
            return true;
        }
    }

    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return msg;
    }

    @Override
    public String toString() {
        return "Result{code=" + this.code + ", errorMsg='" + this.msg + '\'' + ", data=" + this.data + '}';
    }
}
